using System.Buffers;
using System.Net;
using System.Net.Sockets;
using System.Text;
using SuperSocket.ProtoBase;
using SuperSocketProxy.Commands;

namespace SuperSocketProxy;

public sealed class Socket5EndPointPacket : SocketProxyPacket
{
    public Socket5EndPointPacket()
    {
        Key = Command.AuthEndPoint;
    }

    public ushort Port { get; set; }
    
    public EndPoint RemoteEndPoint { get; set; }

    public AddressType AddressType { get; set; }
    
    public ReadOnlySpan<byte> GetAddressSpan()
    {
        if (RemoteEndPoint is DnsEndPoint dnsEndPoint)
            return Encoding.UTF8.GetBytes(dnsEndPoint.Host);
        else if (RemoteEndPoint is IPEndPoint ipEndPoint)
            return ipEndPoint.Address.GetAddressBytes();
        else
            throw new Exception();
    }
    
    public override SocketProxyPacket Decode(ref SequenceReader<byte> reader)
    {
        reader.TryRead(out var protocolVersion);
        reader.TryRead(out var cmd);
        reader.TryRead(out var reserve);
        reader.TryRead(out var type);

        var addressType = (AddressType)type;

        ushort port;
        
        switch (addressType)
        {
            case AddressType.Ipv4://InterNetwork
            case AddressType.Ipv6://InterNetworkV6
                var address = reader.Read(4,4);
                reader.TryReadBigEndian(out port);

                Port = port;
                AddressType = addressType;
                RemoteEndPoint = new IPEndPoint(new IPAddress(address), port);
                break;
            case AddressType.Dns://DnsEndPoint
                var host = reader.ReadStringLengthEncodedWithBit();
                reader.TryReadBigEndian(out port);
                
                Port = port;
                AddressType = addressType;
                RemoteEndPoint = new DnsEndPoint(host, port, AddressFamily.InterNetwork);
                break;
            default:
                throw new NotSupportedException();
        }

        return this;
    }
}

public sealed class Socket5AuthPassPacket : SocketProxyPacket
{
    public Socket5AuthPassPacket()
    {
        Key =  Command.AuthUserPass;
    }

    /// <summary>
    /// 子协议版本
    /// </summary>
    public byte SubProtocolVersion { get; private set; }
    
    /// <summary>
    /// 账号
    /// </summary>
    public string Username { get; private set; }

    /// <summary>
    /// 密码
    /// </summary>
    public string Password { get; private set; }

    public override SocketProxyPacket Decode(ref SequenceReader<byte> reader)
    {
        reader.TryRead(out var subProtocolVersion); //VER为子协议（用户口令认证协议）的版本

        if (subProtocolVersion != 0x01)
            throw new ProtocolException($"subProtocolVersion error , value {subProtocolVersion}");
        
        var userName = reader.ReadStringLengthEncodedWithBit();
        var passWord = reader.ReadStringLengthEncodedWithBit();

        if (string.IsNullOrWhiteSpace(userName) || string.IsNullOrWhiteSpace(passWord))
            throw new UserOrPassException("username or password can not null");
        
        Username = userName;
        Password = passWord;
        SubProtocolVersion = subProtocolVersion;
       
        return this;
    }
}

public sealed class Socket5HandshakePacket : SocketProxyPacket
{
    public Socket5HandshakePacket()
    {
        Key = Command.Handshake;
    }

    public byte AuthCount { get; private set; }
    
    public SocketProxyType ProxyType { get; private set; }
    
    public override SocketProxyPacket Decode(ref SequenceReader<byte> reader)
    {
        reader.TryRead(out var protocolVersion);
        reader.TryRead(out var authCount); //是指有多少个可以使用的方法，也就是客户端支持的多少种认证方法
        reader.TryRead(out var METHODS); //METHODS 就是方法值，有多少个方法就有多少个byte，可以是如下值
        reader.TryRead(out var METHODS1);//METHODS 就是方法值，有多少个方法就有多少个byte，可以是如下值

        AuthCount = authCount;
        ProxyType = (SocketProxyType)protocolVersion;
        
        return this;
    }
}

